#include<curses.h>
#include <stdlib.h>
#include <unistd.h>
#include<pthread.h>

#define UP     1
#define DOWN  -1
#define RIGHT  2
#define LEFT  -2

struct Snake //贪吃蛇身子的一个结点
{
        int hang;
        int lie;
        struct Snake*next;
};

struct Snake food;
void initFood()
{
        int x=rand()%20;
        int y=rand()%20;//%20是为了保证使rand出现的随机数尽量的出现在地图范围内
        food.hang=x;
        food.lie=y;
}
void initNcurses()
{
        initscr();
        keypad(stdscr,1);
        noecho();//不要把无关的东西打印在界面上 
}


struct Snake* head=NULL;//将蛇的头节点定义为全局变量
struct Snake* tail=NULL;//将蛇的尾节点定义为全局变量，防止错误过多
int key;
int dir;

int hasFood(int i,int j)
{
                if(food.hang==i && food.lie==j){
                        return 1;
                }
        return 0;
}
int hasSnakeNode(int i,int j)
{
        struct Snake *p;
        p=head;
        while(p!=NULL){
                if(p->hang==i && p->lie==j){
                        return 1;
                }
                p=p->next;
        }
        return 0;
}
void map()
{
        int hang;
        int lie;
        move(0,0);//在每次调用地图的时候用move函数将光标移动到地图的第一个方格的位置
        for(hang=0;hang<20;hang++){
                if(hang==0){
                        for(lie=0;lie<20;lie++){
                                printw("--");
                        }
                        printw("\n");
                        printw("");
                }
                if(hang>=0&&hang<=19){
                        for(lie=0;lie<=20;lie++){
                                if(lie==0||lie==20){
                                        printw("|");
                                }
                                else if(hasSnakeNode(hang,lie)){
                                        printw("[]");
                                }
                                else if(hasFood(hang,lie)){
                                        printw("**");
                                }
                                else{
                                        printw("  ");
                                }
                        }
                        printw("\n");

                }
                if(hang==19){
                        for(lie=0;lie<20;lie++){
                                printw("--");
                        }
                        printw("\n");
                }
        }
        printw("By Feng Hui Nan.");
}
void addSnake()
{
        struct Snake* new=(struct Snake*)malloc(sizeof(struct Snake));
        new->next=NULL;
        switch(dir){
                case UP:
                        new->hang=tail->hang-1;
                        new->lie=tail->lie;
                        break;
                case DOWN:
                        new->hang=tail->hang+1;
                        new->lie=tail->lie;
                        break;
                case LEFT:
                        new->hang=tail->hang;
                        new->lie=tail->lie-1;
                        break;
                case RIGHT:
                        new->hang=tail->hang;
                        new->lie=tail->lie+1;
                        break;


        }
        tail->next=new;
        tail=new;
}
void initSnake()//蛇的初始化函数
{
        struct Snake*p;
        dir=RIGHT;
        while(head!=NULL){
                p=head;
                head=head->next;//将链表的每一个节点都释放掉，指针后移
                free(p);
        }//添加这个循环的目的是在一次游戏结束后释放当局游戏创建的链表，避免内存泄露
        initFood();
        head=(struct Snake*)malloc(sizeof(struct Snake));
        head->hang=1;
        head->lie=1;
        head->next=NULL;
        tail=head;
        addSnake();
        addSnake();
        addSnake();
}
void deleSnake()
{
        struct Snake*p;
        p=head;
        head=head->next;
        free(p);
}

int ifSnakeDie()
{
        struct Snake*p;
        p=head;
        if(tail->hang<0 || tail->lie==20 || tail->lie==0 || tail->hang==20){
                return 1;
        }
        while(p->next!=NULL){
                if(p->hang==tail->hang && p->lie==tail->lie){
                        return 1;
                }
                p=p->next;
        }
        return 0;

}
void* moveSnake()
{
        addSnake();//在蛇的尾部添加节点并且删除节点后然后判断尾节点的行和列是否达到边界
        if(hasFood(tail->hang,tail->lie)){
                initFood();
        }
        else{
                deleSnake();
        }
        if(ifSnakeDie()){
                initSnake();
        }
}
void* refreshUi()//封装的界面刷新函数
{
        while(1){
                moveSnake();
                map();//删除后再次刷新地图显示移动后的界面
                refresh();//刷新界面函数
                //sleep(1);//每隔一秒蛇移动一下，并刷新界面，这行控制蛇的移动速率
                usleep(150000);//sleep以秒为单位有点慢，usleep以微秒为单位此处控制蛇的移动速度
        }
}
void turn(int direction)//这个函数的作用是当蛇在竖直方向上运动时使上下键无效
                        //在水平方向运动时，左右方向键无效
{
        if(abs(dir)!=abs(direction)){
                dir=direction;
        }
}
void* changeDir()
{
        while(1){
                key=getch();
                switch(key){
                        case KEY_DOWN:
                                turn(DOWN);
                                break;
                        case KEY_UP:
                                turn(UP);
                                break;
                        case KEY_RIGHT:
                                turn(RIGHT);
                                break;
                        case KEY_LEFT:
                                turn(LEFT);
                                break;
                }

        }

}
int main()
{
        initNcurses();
        initSnake();
        map();
        pthread_t t1;
        pthread_t t2;
        int *pthread1=NULL;
        int *pthread2=NULL;
        pthread_create(&t1,NULL,changeDir,NULL);
        pthread_create(&t2,NULL,refreshUi,NULL);
//      pthread_join(t1,(void**)&pthread1);
//      pthread_join(t2,(void**)&pthread2);
        while(1);
        getch();
        endwin();//没有这行会破坏shell终端
        return 0;
}

